﻿extern "C" {
#include "libavutil/frame.h"
#include "libswscale/swscale.h"
#include "libavutil/mem.h"
#include "libavcodec/avcodec.h"
#include "libavutil/imgutils.h"
#include "libavformat/avformat.h"
#include "libavutil/log.h"
#include "libavutil/time.h"
#include "libswresample/swresample.h"
}

#include <SDL.h>
#include <SDL_thread.h>
#include <thread>
#include <functional>

//渲染类型
enum RENDER_TYPE {
    QT_RENDER,          //用Qt绘图直接渲染
    QT_OPENGL_RENDER,   //用Qt opengl渲染
    RENDER_NONE         //没有渲染类型
};

/**
 *音视频同步方式，缺省以音频为基准
 */
enum {
    AV_SYNC_UNKNOW_MASTER = -1,
    AV_SYNC_AUDIO_MASTER,                   // 以音频为基准
    AV_SYNC_VIDEO_MASTER,                   // 以视频为基准
//    AV_SYNC_EXTERNAL_CLOCK,                 // 以外部时钟为基准，synchronize to an external clock */
};

//用于缓存解码后的数据
typedef struct Frame {
    AVFrame		*frame;             // 指向数据帧
    int         serial;             // 帧序列，在seek的操作时serial会变化
    double		pts;                // 时间戳，单位为秒
    double		duration;           // 该帧持续时间，单位为秒
    int64_t     pos;
    int         width;              // 图像宽度
    int         height;             // 图像高读
    int         format;             // 对于图像为(enum AVPixelFormat)
    AVRational  sar;
    int         uploaded;
    int         flip_v;
} Frame;

typedef struct VideoFrame
{
    uint8_t *data[8] = {NULL};         // 类似FFmpeg的buf
    int32_t linesize[8] = {0};
    int32_t width;
    int32_t height;
    int format = AV_PIX_FMT_YUV420P;
}VideoFrame;

#define MAX_QUEUE_SIZE (15 * 1024 * 1024)       //最大队列字节大小
#define MIN_FRAMES 25

//包队列相关
extern AVPacket flush_pkt;             //定义一个flush_pkt用于刷新

typedef struct MyAVPacketList {
    AVPacket		pkt;                //解封装后的数据
    struct MyAVPacketList	*next;      //下一个节点
    int			serial;                 //播放序列
} MyAVPacketList;

typedef struct PacketQueue {
    MyAVPacketList	*first_pkt, *last_pkt;  // 队首和队尾指针
    int		nb_packets;                     // 包数量，也就是队列元素数量
    int		size;                           // 队列所有元素的数据大小总和
    int64_t		duration;                   // 队列所有元素的数据播放持续时间
    int		abort_request;                  // 用户退出请求标志
    int		serial;                         // 播放序列号，和MyAVPacketList的serial作用相同，但改变的时序稍微有点不同
    SDL_mutex	*mutex;                     // 用于维持PacketQueue的多线程安全(SDL_mutex可以按pthread_mutex_t理解）
    SDL_cond	*cond;                      // 用于读、写线程相互通知(SDL_cond可以按pthread_cond_t理解)
} PacketQueue;

//帧队列相关
#define VIDEO_PICTURE_QUEUE_SIZE	3       // 图像帧缓存数量
#define VIDEO_PICTURE_QUEUE_SIZE_MIN        (3)
#define VIDEO_PICTURE_QUEUE_SIZE_MAX        (16)
#define VIDEO_PICTURE_QUEUE_SIZE_DEFAULT    (VIDEO_PICTURE_QUEUE_SIZE_MIN)
#define SUBPICTURE_QUEUE_SIZE		16      // 字幕帧缓存数量
#define SAMPLE_QUEUE_SIZE           9       // 采样帧缓存数量
#define FRAME_QUEUE_SIZE FFMAX(SAMPLE_QUEUE_SIZE, FFMAX(VIDEO_PICTURE_QUEUE_SIZE, SUBPICTURE_QUEUE_SIZE))

#define SDL_AUDIO_MIN_BUFFER_SIZE 512

/* no AV sync correction is done if below the minimum AV sync threshold */
#define AV_SYNC_THRESHOLD_MIN 0.04
/* AV sync correction is done if above the maximum AV sync threshold */
#define AV_SYNC_THRESHOLD_MAX 0.1
/* If a frame duration is longer than this, it will not be duplicated to compensate AV sync */
#define AV_SYNC_FRAMEDUP_THRESHOLD 0.1
/* no AV correction is done if too big error */
#define AV_NOSYNC_THRESHOLD 10.0

/* 这是一个循环队列，windex是指其中的首元素，rindex是指其中的尾部元素. */
typedef struct FrameQueue {
    Frame	queue[FRAME_QUEUE_SIZE];        // FRAME_QUEUE_SIZE  最大size, 数字太大时会占用大量的内存，需要注意该值的设置
    int		rindex;                         // 读索引。待播放时读取此帧进行播放，播放后此帧成为上一帧
    int		windex;                         // 写索引
    int		size;                           // 当前总帧数
    int		max_size;                       // 可存储最大帧数
    int keep_last;
    int rindex_shown;
    SDL_mutex	*mutex;                     // 互斥量
    SDL_cond	*cond;                      // 条件变量
    PacketQueue	*pktq;                      // 数据包缓冲队列
} FrameQueue;

typedef struct AudioParams {
    int			freq;                   // 采样率
    int			channels;               // 通道数
    int64_t		channel_layout;         // 通道布局，比如2.1声道，5.1声道等
    enum AVSampleFormat	fmt;            // 音频采样格式，比如AV_SAMPLE_FMT_S16表示为有符号16bit深度，交错排列模式。
    int			frame_size;             // 一个采样单元占用的字节数（比如2通道时，则左右通道各采样一次合成一个采样单元）
    int			bytes_per_sec;          // 一秒时间的字节数，比如采样率48Khz，2 channel，16bit，则一秒48000*2*16/8=192000
} AudioParams;

// 这里讲的系统时钟 是通过av_gettime_relative()获取到的时钟，单位为微妙
typedef struct Clock {
    double	pts;            // 时钟基础, 当前帧(待播放)显示时间戳，播放后，当前帧变成上一帧
    // 当前pts与当前系统时钟的差值, audio、video对于该值是独立的
    double	pts_drift;      // clock base minus time at which we updated the clock
    // 当前时钟(如视频时钟)最后一次更新时间，也可称当前时钟时间
    double	last_updated;   // 最后一次更新的系统时钟
    double	speed;          // 时钟速度控制，用于控制播放速度
    // 播放序列，所谓播放序列就是一段连续的播放动作，一个seek操作会启动一段新的播放序列
    int	serial;             // clock is based on a packet with this serial
    int	paused;             // = 1 说明是暂停状态
    // 指向packet_serial
    int *queue_serial;      /* pointer to the current packet queue serial, used for obsolete clock detection */
} Clock;

